- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有一些运行 apache trafficserver 的 linux 服务器,发现大约 1/20 的请求需要几毫秒,这比预期的要长得多(应该是 1-2 毫秒)。
通过 systemtap 跟踪后,我发现时间花在了 linux 内核 copy_to_user() 调用上。 (accept->inet_csk_accept->move_addr_to_user->copy_to_user)
服务器负载很低 (<100qps) 并且 copy_to_user() 只复制 16 个字节的数据 (struct sockaddr) 但花费了数百毫秒。
由于我是 systemtap 和内核跟踪技术的新手,我无法调查进一步的原因。我检查了 cpu 使用情况,swap 使用情况
感谢您的任何建议。
硬件:
软件:
nginx 1.10.2,代理用户请求到trafficserver
// systemtap
probe kernel.function("move_addr_to_user")
{
ts["move_addr_to_user", pid()] = gettimeofday_ms()
}
probe kernel.function("move_addr_to_user").return
{
printf("[%d]move_addr_to_user done:%d %s %d\n", gettimeofday_ms(), pid(), execname(), gettimeofday_ms()-ts["move_addr_to_user", pid()])
}
probe kernel.function("copy_to_user")
{
ts["copy_to_user", pid()] = gettimeofday_ms()
}
probe kernel.function("copy_to_user").return
{
printf("[%d]copy_to_user done:%d %s %d %d\n", gettimeofday_ms(), pid(), execname(), gettimeofday_ms()-ts["copy_to_user", pid()],
gettimeofday_ms()-ts["__copy_to_user", pid()])
}
// output:
[1495630190767] 16 16 move_addr_to_user done:24145 [ACCEPT 0:8080] 0
[1495630191164]copy_to_user done:24145 [ACCEPT 0:8080] 0
[1495630191164] 16 16 move_addr_to_user done:24145 [ACCEPT 0:8080] 0
[1495630192172]copy_to_user done:24145 [ACCEPT 0:8080] 861
[1495630192172] 16 16 move_addr_to_user done:24145 [ACCEPT 0:8080] 861
[1495630192173]copy_to_user done:24145 [ACCEPT 0:8080] 0
[1495630192173] 16 16 move_addr_to_user done:24145 [ACCEPT 0:8080] 0
[1495630192173]copy_to_user done:24145 [ACCEPT 0:8080] 0
[1495630192173] 16 16 move_addr_to_user done:24145 [ACCEPT 0:8080] 0
[1495630192173]copy_to_user done:24145 [ACCEPT 0:8080] 0
free -g
total used free shared buffers cached
Mem: 62 55 6 0 0 32
-/+ buffers/cache: 23 39
Swap: 15 0 15
top - 20:57:39 up 24 days, 19:26, 2 users, load average: 7.70, 9.43, 9.62
Tasks: 643 total, 1 running, 642 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.1%us, 1.0%sy, 0.0%ni, 97.5%id, 1.1%wa, 0.0%hi, 0.3%si, 0.0%st
Mem: 65560992k total, 58525192k used, 7035800k free, 365084k buffers
Swap: 16777212k total, 0k used, 16777212k free, 33957572k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
24145 traffics 20 0 21.7g 12g 6212 S 24.7 19.3 212:42.85 [ET_NET 0]
22173 root 20 0 677m 325m 1180 S 3.6 0.5 0:41.10 nginx
22161 root 20 0 677m 325m 1184 S 2.6 0.5 0:47.50 nginx
22168 root 20 0 677m 326m 2076 S 2.6 0.5 0:28.31 nginx
22150 root 20 0 677m 325m 1208 S 1.6 0.5 0:42.75 nginx
22165 root 20 0 677m 325m 1200 S 1.6 0.5 0:31.77 nginx
更新:
@employee of the month 感谢您的建议,在对 __do_page_fault 添加一些探测后,我发现时间花在了 __do_page_fault -> down_read(&mm->mmap_sem);
[1495677639202]copy_to_user done:24145 [ACCEPT 0:8080] 1
[1495677639202] 16 16 move_addr_to_user done:24145 [ACCEPT 0:8080] 1
[1495677639314]copy_to_user done:24145 [ACCEPT 0:8080] 0
[1495677639314] 16 16 move_addr_to_user done:24145 [ACCEPT 0:8080] 0
[1495677641329]do page fault done:24145 [ACCEPT 0:8080] 622
[1495677641329]copy_to_user done:24145 [ACCEPT 0:8080] 622
[1495677641329] 16 16 move_addr_to_user done:24145 [ACCEPT 0:8080] 622
@Ricardo Biehl Pasquali 感谢您的建议。 Apache trafficserver 在单独的线程中读/写到 hdd。 trafficserver 有 1 个线程来接受连接,88(每个硬盘 8 个线程)线程来阻塞读/写(缓存内容),但我不明白为什么在其他线程中阻塞读/写会导致 __do_page_fault() 的高延迟.
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 16.00 0.00 4.00 0.00 160.00 40.00 0.05 13.50 0.00 13.50 7.75 3.10
sdi 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sde 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdd 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdj 0.00 0.00 6.00 0.00 4326.00 0.00 721.00 0.06 10.50 10.50 0.00 6.83 4.10
sdc 0.00 0.00 2.00 0.00 1472.00 0.00 736.00 0.04 18.50 18.50 0.00 9.50 1.90
sdh 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdg 0.00 0.00 14.00 0.00 10464.00 0.00 747.43 0.04 2.71 2.71 0.00 1.79 2.50
更新:
问题解决了!根本原因是 trafficserver 在我们写的一个古老的插件中定期调用 system() 来备份文件。
最佳答案
好吧,合理的解释是您遇到了页面错误。一个可能的原因是服务器根据负载的变化而 fork /退出,并且新的 child 必须对页面进行错误处理,但作为一个小错误,除非内存不足,否则不会花费很长时间。
另一个是内存不足,你实际上是在交换。
无论哪种方式,鉴于您已经走到这一步,我看不出还有什么问题。您想将探测器放在 __do_page_fault 上并从那里继续。
关于c++ - 为什么 copy_to_user 会花费数百毫秒?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44159015/
我已经为我的内核模块实现了一个字符设备,并为其实现了一个读取函数。读取函数调用copy_to_user将数据返回给调用者。我最初以阻塞方式实现读取功能(使用 wait_event_interrupti
我的内核驱动程序中有一个 ioctl,需要在读取时返回一些数据。当我在用户空间中读回它时,它没有显示预期的结果。 用户空间片段: typedef struct abc_T { int size
当条件失败时,我正在尝试从内核空间向用户空间获取一些消息! 这是我的内核代码: #define MESSAGTOUSER 1 int ret_val; struct siginfo sinfo; pi
我需要将内核空间中的curr_task->pid,一个pid_t,复制到用户空间中一个结构体的域中,该结构体的域有很长的空间。由于这是一个不断扩大的转换,我预计不会出现任何问题。 但是,我收到了一个烦
我必须在 Linux 内核中添加一个系统调用,该系统调用将打印进程树,仅显示用户代码的 PID。我必须在这里使用 copy_to_user 。但我不明白这个功能的用途。你们中的任何人都可以举一个例子来
copy_to_user 和 copy_from_user 函数在 Linux 系统的什么地方定义和实现? 最佳答案 它在 asm/uaccess.h 中定义,例如,在 /usr/src/linux-
我一直被告知(在书籍和教程中)在将数据从内核空间复制到用户空间时,我们应该使用 copy_to_user() 并且使用 memcpy() 会给系统带来问题。最近我错误地使用了 memcpy(),它工作
我试图在内核模块读取函数中使用 copy_to_user,但无法将数据从内核复制到用户缓冲区。如果我做错了什么,谁能告诉我。我的内核版本是 2.6.35。我给出了内核模块的一部分以及用于测试它的应用程
我正在尝试将自定义系统调用添加到 linux 内核中。这是一个简单的代码: #include #include #include #include asmlinkage int sys_mys
我正在 Linux 内核中编写一个系统调用,它给定一个虚拟地址和一个无符号长指针,找到相应的页表条目,然后将其内容复制到无符号长指针中。这是系统调用: SYSCALL_DEFINE2(readMMU,
在用户空间程序中,我通过 mmap 分配一些内存,如下函数调用: void *memory; int fd; fd = open(filepath, O_RDWR); if (fd < 0) r
我了解到,当 copy_to_user 函数发生页面错误时,将使用异常表。 但我发现几乎所有的修复都会设置返回值并跳转到触发页面错误的指令之后的下一条指令。 内核在哪里做用户空间地址的映射工作? 我的
我有一个邮箱链接列表,我正在尝试将它们的 ID 复制到用户空间变量 mbxList,但打印不正确。 asmlinkage long sys_listMailboxes(unsigned long *
这个问题在这里已经有了答案: copy_to_user vs memcpy (2 个答案) 关闭 7 年前。 让我们考虑以下代码。对于阅读 Linux 设备驱动程序的人来说,上下文会很清楚。 简而言
我一直认为当内核通过 procfs 写入用户时,copy_to_user 是必要的。 虽然我忘了做一次(我使用了 snprintf),但一切正常。既然我注意到了,我就一直在寻找。我找到了 this l
为什么内核要使用copy_to_user函数? 直接操作用户空间的数据不行吗? 最佳答案 内核和用户空间应用程序具有不同的地址空间,因此复制到用户空间需要更改地址空间。每个进程都有自己的(用户)地址空
我正在尝试定义一个系统调用来修改传递给它的字符缓冲区。具体来说,像这样: ... asmlinkage int sys_mycall( char __user *buff, int len ) {
以下是我的简单驱动程序代码的摘录。 int vprobe_ioctl( struct file *filep, unsigned int cmd, void *UserInp) { case
我正在开发 Linux 驱动程序,发现在某些情况下 copy_to_user() 花费的时间比预期的要长得多。我想它可能正在等待 mm->mmap_sem 信号量,也许吧?在不利情况下似乎还有额外的
披露:我是 C 的新手。如果您能详细解释任何答案,我将不胜感激。 我正在编写一个 linux 内核模块,在我正在编写的其中一个函数中,我需要将一个结构复制到用户空间,如下所示: typedef str
我是一名优秀的程序员,十分优秀!